﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace XForms.BaseComponents
{
    public abstract class BaseControl : BaseUI
    {
        public BaseForm Owner { get; protected set; }

        public Boolean HasOwner { get; protected set; }

#if WINDOWS
        public BaseControl(Game game, String name, BaseForm owner = null)
            : base(game, name)
#elif WINDOWS_PHONE
        public BaseControl(Game game, String name, BaseForm owner)
            : base(game, name)
#endif
        {
            //Check if the owning form is null.
            //User is using this control directly on the screen.
            if (owner == null)
                this.HasOwner = false;
            else
            {
                this.Owner = owner;
                this.HasOwner = true;
            }

            if (this.HasOwner)
                this.Owner.ControlCollection.Add(this);

            //Setup border info
            this.BorderOnTop = true;
            this.HasBorder = true;

            //Set various properties
            this.CanClose = true;
            this.Enabled = true;
            this.IsHidden = true;
            this.IsStatic = false;
            this.IsTextVisible = true;

            this.Visible = false;

            //Event methods.
            this.OnShowEvent += new OnShowHandler(OnShow);
            this.OnHideEvent += new OnHideHandler(OnHide);
            this.OnCloseEvent += new OnCloseHandler(OnClose);
            this.OnClickEvent += new OnClickHandler(OnClick);
            this.OnUpdateEvent += new OnUpdateHandler(OnUpdate);
            this.OnDrawEvent += new OnDrawHandler(OnDraw);
            this.OnMoveEvent += new OnMoveHandler(OnMove);
            this.OnMouseOverEvent += new OnMouseOverHandler(OnMouseOver);
        }

        public override void Initialize()
        {
            base.Initialize();
            //Setup the Size & Location
            if (this.HasOwner)
            {
                int x, y;

                this.Size = new BaseComponents.Size(Owner.Size.Width / 2, Owner.Size.Height / 3);

                //Center of the Owner
                x = (int)this.Owner.Center.X - (this.Size.Width / 2);
                y = (int)this.Owner.Center.Y - (this.Size.Height / 2);
                this.Location = new Vector2(x, y);
            }
            else
            {
                this.Size = new Size(this.Game.GraphicsDevice.Viewport.Width / 4, this.Game.GraphicsDevice.Viewport.Height / 8);
                this.Location = new Vector2(10, 10); //Offset from edge of screen a little.
            }

            //Setup Colors and border info
            this.SetBackgroundColor(Color.Brown);
            this.SetTextColor(Color.Gray);
        }

        public override void Update(GameTime gameTime)
        {
            if (this.Visible && !this.IsHidden)
            {
                this.OnUpdateEvent(this, gameTime);
            }
        }

        public override void Draw(GameTime gameTime)
        {
            this.OnDrawEvent(this, gameTime);

            base.Draw(gameTime);
        }

        public virtual void SetOwner(BaseForm owner)
        {
            if (owner == null)
                return;

            this.Owner = owner;
            this.HasOwner = true;
        }
        public override void Show()
        {
            this.Visible = true;
            this.IsHidden = false;

            this.OnShowEvent(this);
        }

        public override void Close()
        {
            bool cancel = false;

            this.OnCloseEvent(this, out cancel);

            if (cancel)
                return;
        }

        public override void Hide()
        {
            this.OnHideEvent(this);
        }

        public delegate void OnShowHandler(BaseUI sender);
        public event OnShowHandler OnShowEvent;
        public override void OnShow(BaseUI sender)
        {

        }

        public delegate void OnCloseHandler(BaseUI sender, out bool cancel);
        public event OnCloseHandler OnCloseEvent;
        public override void OnClose(BaseUI sender, out bool cancel)
        {
            cancel = false;
        }

        public delegate void OnHideHandler(BaseControl sender);
        public event OnHideHandler OnHideEvent;
        public override void OnHide(BaseUI sender)
        {
        }

        public delegate void OnClickHandler(BaseUI sender);
        public event OnClickHandler OnClickEvent;
        public override void OnClick(BaseUI sender)
        {
            if (!this.IsStatic)
            {
                MouseState mouse = Mouse.GetState();

                Vector2 currentPos = new Vector2(mouse.X, mouse.Y);
                if (Vector2.Distance(currentPos, MouseOrigin) > 1)
                {
                    this.IsMoving = true;
                    this.OnMoveEvent(this);
                }
                else
                    this.IsMoving = false;
            }
        }

        public delegate void OnMoveHandler(BaseUI sender);
        public event OnMoveHandler OnMoveEvent;
        public override void OnMove(BaseUI sender)
        {
            MouseState mouse = Mouse.GetState();

            //Get the mouse offset so that the upper left corner of the Control
            //doesn't always snap to the mouse location.
            Vector2 offset = new Vector2(this.MouseOrigin.X - this.ControlOrigin.X, this.MouseOrigin.Y - this.ControlOrigin.Y);
            Vector2 newLocation = new Vector2(mouse.X - offset.X, mouse.Y - offset.Y);

            //If we are contained on a Owning Form, then check for bounds.
            //We don't want to allow the Control to leave the Form.
            if (this.HasOwner)
            {
                //Left Size bound check
                if (newLocation.X <= this.Owner.Location.X)
                    newLocation.X = this.Owner.Location.X;
                //Right side bound check.  Must consider control width during checks.
                if (newLocation.X + this.Size.Width >= this.Owner.Location.X + this.Owner.Size.Width)
                    newLocation.X = this.Owner.Location.X + this.Owner.Size.Width - this.Size.Width;
                //Check the Height.  If we have a Titlebar then take that into consideration
                if (this.Owner.HasTitleBar)
                {
                    //If we have a title bar, force the Control to butt-up against it
                    if (newLocation.Y <= this.Owner.Location.Y + this.Owner.TitleBarSize)
                        newLocation.Y = this.Owner.Location.Y + this.Owner.TitleBarSize;
                }
                else
                {
                    //if we don't have a title bar, then allow the Control to
                    //butt-up against the top of the Form edge.
                    if (newLocation.Y <= this.Owner.Location.Y)
                        newLocation.Y = this.Owner.Location.Y;
                }
                //Check the Height.  Bottom boundry check
                if (newLocation.Y + this.Size.Height >= this.Owner.Location.Y + this.Owner.Size.Height)
                    newLocation.Y = this.Owner.Location.Y + this.Owner.Size.Height - this.Size.Height;
            }

            this.Location = newLocation;
        }

        public delegate void OnMouseOverHandler(BaseUI sender);
        public event OnMouseOverHandler OnMouseOverEvent;
        public override void OnMouseOver(BaseUI sender)
        {
    
        }

        public delegate void OnUpdateHandler(BaseUI sender, GameTime gameTime);
        public event OnUpdateHandler OnUpdateEvent;
        public override void OnUpdate(BaseUI sender, GameTime gameTime)
        {
            MouseState mouse = Mouse.GetState();

            this.UpdateMousePosition(gameTime);

            if (this.IsMouseOver)
                this.OnMouseOverEvent(this);

            //Check to make sure that we are over the UI Component before firing
            //the OnClick event
            if (mouse.LeftButton == ButtonState.Pressed && this.IsMouseOver)
            {
                Boolean ignoreEvent = false;

                if (this.HasOwner)
                {
                    foreach (BaseControl control in this.Owner.ControlCollection)
                    {
                        //We don't want to fire the event due to the user
                        //currently moving another control over the top of this.
                        if (control.IsMoving && control.Name != this.Name)
                        {
                            ignoreEvent = true;
                            break;
                        }
                    }
                }

                if (!ignoreEvent)
                {
                    //Capture the initial location of the mouse before we start moving
                    if (!this.IsMouseDown)
                    {
                        this.ControlOrigin = new Vector2(this.Location.X, this.Location.Y);
                        this.MouseOrigin = new Vector2(mouse.X, mouse.Y);
                    }
                    this.IsMouseDown = true;
                    this.OnClickEvent(this);
                }
            }
            else
            {
                this.IsMoving = false;
                this.IsMouseDown = false;
            }
        }

        public delegate void OnDrawHandler(BaseUI sender, GameTime gameTime);
        public event OnDrawHandler OnDrawEvent;
        public override void OnDraw(BaseUI sender, GameTime gameTime)
        {
            //If we are not visible we don't want to render.
            //Rrgardless if it's just 'hidden' but still running.
            if ((!this.Visible) || (this.IsHidden))
                return;

            this.SpriteBatch.Begin();

            //Draw the forms background.
            this.SpriteBatch.Draw(this.BackgroundMaterial, this.Interface, null, Color.Lerp(Color.White, Color.Transparent, MathHelper.Clamp(this.Transparency, 0,1)), this.Rotation, new Vector2(), SpriteEffects.None, this.DrawOrder);

            //If we have text specified and the following requirements are met:
            //1: Font is not NULL  2: Text is not NULL
            //Then render the text to the center of the Title Bar.
            //TODO: Provide Location Presets such as Left, Center, Right, etc.
            if (this.IsTextVisible && this.Font != null && !String.IsNullOrEmpty(this.Text))
            {
                int centerX = (this.Interface.X + this.Interface.Width / 2) - (int)(this.Font.MeasureString(Text).X / 2);
                Vector2 center = new Vector2(centerX, this.Interface.Y);

                this.SpriteBatch.DrawString(this.Font, this.Text, center, this.TextColor, this.Rotation, new Vector2(), 1.0f, SpriteEffects.None, this.DrawOrder);
            }

            this.SpriteBatch.End();
        }
    }
}
